module ReqImportLib

class Line

  attr_accessor :type, :for_refs, :text, :ref, :req, :error, :id, :result, :duplicates, :id
  
  def initialize id
    @id    = id
    @type  = :unknown
    @error = nil
    @duplicates = []
    @for_refs = []
  end

end

class Doc

  attr_reader :content, :lines

  def initialize(params)
    if params[:content]
      @content = params[:content].split("\n")
    elsif params[:file]
      @content = File.open(params[:file]).readlines
    else
      @content = []
    end
    parse
  end

  def parse
    @lines = []
    @content.each_with_index { |@current_line, i|
      line = Line.new(i+1)
      set_type line
      @lines << line
      #puts "#{line.ref}: #{line.req} (#{line.for_ref})" and next if line.type == :req
      #puts "#{line.error} (#{line.text.chomp})" if line.error != nil
      }
    # cleaning
    @lines.each { |line|
      line.for_refs.flatten.map{ |ref| ref.strip }.uniq!
      }
  
  end
  
  def set_type line
    line.text = @current_line
    line.result = :succeed
    if @current_line[0].chr == '-' # it is a new req
      line.type = :req
      line.for_refs << @current_refs if @current_refs
      parse_req line
      @current_req = line.ref
    elsif  @current_line[0] == 13 # ignore blank lines
      line.type = :blank
      line.result = :fails
      @current_refs = []
      @current_req = nil
    elsif @current_line[0].chr != '#' and @current_line.include?( ?: ) # it is a reference for following reqs # and not @current_line.split(':')[0].strip.include?(' ')
      line.type = :ref
      @current_refs = @current_line.split(':')[0].split(',')
      line.req = @current_refs.join('/')
    else # comments for preceding req
      line.type = :comment
      line.req = @current_line
      line.result = :fails if @current_refs == []
      line.for_refs << @current_req if @current_req
    end  
  end
  
  def comments(ref)
    rv = []
    @lines.each { |line|
      next if line.type != :comment
      next if not line.for_refs.include?(ref)
      rv << line.req
      }
    rv  
  end

  def parse_req line
    arr = line.text.split(':')
    if arr.size < 2
      line.error = "no semicolon on line #{line.id}"
      line.type = :error
      line.result = :fails
      return
    end  
    line.ref = arr[0][2..-1].strip
    line.req = arr[1][0..-2].strip
  end
  
  def add_db(reqs)
    i = @lines.size + 1
    reqs.each { |r|
      line = Line.new(i)
      line.type = :db
      line.ref = r[0]
      line.req = r[1]
      #line.for_refs # TODO
      i += 1
      @lines << line
      }
  end
  
  def flag_duplicates
    @lines.each { |line|
      next if line.type != :req
      d = find_other_ref(line.ref, line)
      if d
        line.duplicates << d.ref
        line.result = :duplicate
      end  
      }
  end

private

  def find_other_ref(ref, exclude_line=nil)
    @lines.each { |l|
      next if l == exclude_line
      return l if l.ref == ref
      }
    return nil  
  end  
end

end

